package miggy.cpu;

import miggy.api.cpu.Instruction;
import miggy.api.cpu.InstructionSet;
import miggy.cpu.instructions.UNKNOWN;
import miggy.utils.TextUtil;

import java.io.*;
import java.util.logging.Logger;

/*
//  Miggy - Java Amiga MachineCore
//  Copyright (c) 2008, Tony Headford
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
//  following conditions are met:
//
//    o  Redistributions of source code must retain the above copyright notice, this list of conditions and the
//       following disclaimer.
//    o  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
//       following disclaimer in the documentation and/or other materials provided with the distribution.
//    o  Neither the name of the Miggy Project nor the names of its contributors may be used to endorse or promote
//       products derived from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
//  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
//  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Revision: 21 $
*/
public class InstructionSetFactory implements InstructionSet
{
	public static final int MAX_INSTRUCTIONS = 0x00010000;
	private Instruction[] list;
	private int count;
	private static final String thisClass = InstructionSetFactory.class.getName();
	private static final Logger logger = Logger.getLogger(thisClass);
	private static final Instruction Unknown = new UNKNOWN();

	public final void add(int opcode, Instruction i)
	{
		logger.config("Instruction 0x" + TextUtil.toHex((short)opcode) + " added");

		Instruction old = list[opcode & 0xFFFF];
		if(old != null)
		{
			logger.warning("Instruction " + old + " already at " + TextUtil.toHex((short)opcode));
			throw new IllegalArgumentException("Instruction " + old + " already at " + TextUtil.toHex((short)opcode));
		}

		list[opcode & 0xFFFF] = i;
		count++;
	}

	public final Instruction get(int opcode)
	{
		Instruction i = list[opcode & 0xFFFF];
		if(i == null)
			return Unknown;

		return i;
	}

	private InstructionSetFactory()
	{
		list = new Instruction[MAX_INSTRUCTIONS];
		count = 0;
	}

	public final int count()
	{
		return count;
	}
	
	public static InstructionSet load(File opsFile)
	{
		InstructionSetFactory iset = new InstructionSetFactory();
		try
		{
			BufferedReader buf = new BufferedReader(new FileReader(opsFile));
			String line;
			while((line = buf.readLine()) != null)
			{
				if(line.startsWith("#"))
					continue;

				Class c = Class.forName(line);
				Class[] intfs = c.getInterfaces();
				for(Class ic: intfs)
				{
					if(ic == Instruction.class)
					{
						logger.config("Loading: " + c.getName());
						Instruction i = Instruction.class.cast(c.newInstance());
						i.register(iset);
					}
				}
			}

/*
			//check which slots are free
			for(int i = 0; i < MAX_INSTRUCTIONS; i++)
			{
				if(iset.list[i] == null)
				{
					logger.info("Empty instruction slot code: 0x" + TextUtil.toHex((short)i));
				}
			}
*/
		}
		catch(FileNotFoundException e)
		{
			//todo: something
			e.printStackTrace();
		}
		catch(IOException e)
		{
			//todo: something
			e.printStackTrace();
		}
		catch(ClassNotFoundException e)
		{
			//todo: something
			e.printStackTrace();
		}
		catch(InstantiationException e)
		{
			//todo: something
			e.printStackTrace();
		}
		catch(IllegalAccessException e)
		{
			//todo: something
			e.printStackTrace();
		}
		return iset;
	}
}
